#include "./../../../include/online/Reactor/Acceptor.h"
#include <stdio.h>

// 构造函数：接受IP地址和端口号，初始化套接字和地址对象
Acceptor::Acceptor(const string &ip, unsigned short port)
:_sock()  // 使用成员初始化列表初始化套接字对象
,_addr(ip, port)  // 使用ip和端口号初始化地址对象
{
    // 在构造函数中，不需要进行其他操作
}

// 析构函数：这里没有显式的资源释放操作，因为Sock类可能会自动管理资源
Acceptor::~Acceptor()
{
    // 默认析构函数，若需要显式释放资源可以在此进行
}

// 准备工作：设置套接字属性，绑定地址，开始监听
void Acceptor::ready()
{
    // 设置地址复用
    setReuseAddr();
    // 设置端口复用
    setReusePort();
    // 绑定地址到套接字
    bind();
    // 启动监听，准备接受连接
    listen();
}

// 接受一个连接请求：通过accept系统调用等待并接受客户端连接
int Acceptor::accept()
{
    // 调用系统调用accept等待客户端连接
    int connfd = ::accept(_sock.getfd(), nullptr, nullptr);
    if(connfd == -1)
    {
        // 如果accept返回-1，说明出错，打印错误信息并返回-1
        perror("accept");
        return -1;
    }
    // 返回新的连接套接字描述符，表示与客户端的连接
    return connfd;
}

// 设置地址复用：允许多个套接字绑定到相同地址
void Acceptor::setReuseAddr()
{
    int opt = 1;  // 设置选项为1，表示启用地址复用
    // 使用setsockopt系统调用设置SO_REUSEADDR选项
    int ret = setsockopt(_sock.getfd(), SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(ret)
    {
        // 如果设置失败，打印错误信息
        perror("setsockopt");
        return;
    }
}

// 设置端口复用：允许多个套接字绑定到相同端口
void Acceptor::setReusePort()
{
    int opt = 1;  // 设置选项为1，表示启用端口复用
    // 使用setsockopt系统调用设置SO_REUSEPORT选项
    int ret = setsockopt(_sock.getfd(), SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
    if(ret == -1)
    {
        // 如果设置失败，打印错误信息
        perror("setsockopt");
        return;
    }
}

// 绑定地址：将套接字与特定的IP和端口绑定
void Acceptor::bind()
{
    // 使用bind系统调用将套接字与地址绑定
    int ret = ::bind(_sock.getfd(), (struct sockaddr*)_addr.getInetAddressPtr(), sizeof(struct sockaddr));
    if(ret == -1)
    {
        // 如果bind失败，打印错误信息
        perror("bind");
        return;
    }
}

// 启动监听：使套接字开始监听客户端连接
void Acceptor::listen()
{
    // 使用listen系统调用启动监听，最多允许128个连接排队
    int ret = ::listen(_sock.getfd(), 128);
    if(ret == -1)
    {
        // 如果listen失败，打印错误信息
        perror("listen");
        return;
    }
}

// 获取套接字描述符：返回当前对象关联的套接字描述符
int Acceptor::fd() const
{
    return _sock.getfd();  // 返回套接字的文件描述符
}
